"""
AI Agent Pro - 智能体核心引擎
"""

import asyncio
import json
import time
import uuid
from typing import Any, Dict, List, Optional, Union, AsyncGenerator
from enum import Enum

from pydantic import BaseModel, Field

from app.core.config import get_settings
from app.core.exceptions import AgentException, ModelError, ToolError
from app.core.logging import get_logger, log_agent_action, log_tool_usage
from app.agents.models.base import AgentModel
from app.agents.models.openai_model import OpenAIModel
from app.agents.models.anthropic_model import AnthropicModel
from app.tools.base import BaseTool, ToolResult
from app.memory.manager import MemoryManager

logger = get_logger(__name__)
settings = get_settings()


class AgentState(str, Enum):
    """智能体状态枚举"""
    IDLE = "idle"
    THINKING = "thinking"
    ACTING = "acting"
    WAITING = "waiting"
    ERROR = "error"
    STOPPED = "stopped"


class Message(BaseModel):
    """消息模型"""
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    role: str = Field(..., description="消息角色: user, assistant, system")
    content: str = Field(..., description="消息内容")
    timestamp: float = Field(default_factory=time.time)
    metadata: Dict[str, Any] = Field(default_factory=dict)


class Thought(BaseModel):
    """思考过程模型"""
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    type: str = Field(..., description="思考类型: reasoning, planning, reflection")
    content: str = Field(..., description="思考内容")
    confidence: float = Field(default=1.0, ge=0.0, le=1.0)
    timestamp: float = Field(default_factory=time.time)
    metadata: Dict[str, Any] = Field(default_factory=dict)


class Action(BaseModel):
    """行动模型"""
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    tool_name: str = Field(..., description="工具名称")
    parameters: Dict[str, Any] = Field(default_factory=dict)
    reasoning: str = Field(..., description="行动理由")
    expected_outcome: str = Field(..., description="预期结果")
    timestamp: float = Field(default_factory=time.time)


class ExecutionResult(BaseModel):
    """执行结果模型"""
    action_id: str = Field(..., description="行动ID")
    success: bool = Field(..., description="是否成功")
    result: Any = Field(default=None, description="执行结果")
    error: Optional[str] = Field(default=None, description="错误信息")
    duration: float = Field(..., description="执行耗时(秒)")
    timestamp: float = Field(default_factory=time.time)


class AgentConfig(BaseModel):
    """智能体配置"""
    name: str = Field(..., description="智能体名称")
    description: str = Field(default="", description="智能体描述")
    model: str = Field(default="gpt-4", description="使用的AI模型")
    temperature: float = Field(default=0.7, ge=0.0, le=2.0, description="创造性温度")
    max_tokens: int = Field(default=2000, gt=0, description="最大生成token数")
    system_prompt: str = Field(default="", description="系统提示词")
    tools: List[str] = Field(default_factory=list, description="可用工具列表")
    max_iterations: int = Field(default=10, gt=0, description="最大迭代次数")
    thinking_enabled: bool = Field(default=True, description="是否启用思考过程")
    memory_enabled: bool = Field(default=True, description="是否启用记忆功能")
    learning_enabled: bool = Field(default=False, description="是否启用学习功能")
    safety_checks: bool = Field(default=True, description="是否启用安全检查")
    timeout: int = Field(default=300, gt=0, description="执行超时时间(秒)")


class Agent:
    """智能体核心类"""
    
    def __init__(
        self,
        config: AgentConfig,
        tools: Optional[Dict[str, BaseTool]] = None,
        memory_manager: Optional[MemoryManager] = None
    ):
        self.id = str(uuid.uuid4())
        self.config = config
        self.state = AgentState.IDLE
        self.iteration_count = 0
        
        # 初始化AI模型
        self.model = self._initialize_model()
        
        # 初始化工具
        self.tools = tools or {}
        
        # 初始化记忆管理器
        self.memory_manager = memory_manager
        
        # 对话历史
        self.conversation_history: List[Message] = []
        
        # 思考过程
        self.thoughts: List[Thought] = []
        
        # 执行结果
        self.execution_results: List[ExecutionResult] = []
        
        # 性能统计
        self.stats = {
            "total_messages": 0,
            "total_actions": 0,
            "successful_actions": 0,
            "failed_actions": 0,
            "total_thinking_time": 0.0,
            "total_execution_time": 0.0,
            "average_response_time": 0.0
        }
        
        logger.info(f"智能体 {self.id} 初始化完成: {self.config.name}")
    
    def _initialize_model(self) -> AgentModel:
        """初始化AI模型"""
        model_configs = settings.get_ai_model_config()
        
        if self.config.model.startswith("gpt"):
            if "openai" not in model_configs:
                raise ModelError(self.config.model, "OpenAI API密钥未配置")
            return OpenAIModel(
                model_name=self.config.model,
                api_key=model_configs["openai"]["api_key"],
                temperature=self.config.temperature,
                max_tokens=self.config.max_tokens
            )
        
        elif self.config.model.startswith("claude"):
            if "anthropic" not in model_configs:
                raise ModelError(self.config.model, "Anthropic API密钥未配置")
            return AnthropicModel(
                model_name=self.config.model,
                api_key=model_configs["anthropic"]["api_key"],
                temperature=self.config.temperature,
                max_tokens=self.config.max_tokens
            )
        
        else:
            raise ModelError(self.config.model, f"不支持的模型: {self.config.model}")
    
    async def chat(
        self,
        user_message: str,
        user_id: Optional[str] = None,
        stream: bool = False
    ) -> Union[str, AsyncGenerator[str, None]]:
        """
        与智能体对话
        
        Args:
            user_message: 用户消息
            user_id: 用户ID
            stream: 是否流式返回
        
        Returns:
            智能体回复或流式生成器
        """
        start_time = time.time()
        
        try:
            # 更新状态
            self._update_state(AgentState.THINKING)
            
            # 添加用户消息到历史
            user_msg = Message(
                role="user",
                content=user_message,
                metadata={"user_id": user_id}
            )
            self.conversation_history.append(user_msg)
            
            # 记录用户消息
            log_agent_action(
                agent_id=self.id,
                action="USER_MESSAGE",
                user_id=user_id,
                message_length=len(user_message)
            )
            
            # 执行智能体推理循环
            if stream:
                return self._process_stream(user_message, user_id)
            else:
                response = await self._process_message(user_message, user_id)
                
                # 更新统计
                end_time = time.time()
                duration = end_time - start_time
                self._update_stats(duration)
                
                return response
        
        except Exception as e:
            self._update_state(AgentState.ERROR)
            logger.error(f"智能体 {self.id} 处理消息时发生错误: {str(e)}")
            raise AgentException(f"智能体处理失败: {str(e)}")
    
    async def _process_message(self, user_message: str, user_id: Optional[str]) -> str:
        """处理消息的核心逻辑"""
        self.iteration_count = 0
        
        while self.iteration_count < self.config.max_iterations:
            self.iteration_count += 1
            
            # 构建提示词
            prompt = await self._build_prompt(user_message)
            
            # 思考阶段
            if self.config.thinking_enabled:
                await self._think(prompt)
            
            # 生成回复
            response = await self._generate_response(prompt)
            
            # 检查是否需要使用工具
            if self._should_use_tool(response):
                # 解析工具调用
                action = self._parse_tool_call(response)
                if action:
                    # 执行工具
                    result = await self._execute_tool(action)
                    
                    # 如果工具执行成功，继续迭代
                    if result.success:
                        continue
                    else:
                        # 工具执行失败，返回错误信息
                        return f"抱歉，工具执行失败: {result.error}"
            
            # 没有工具调用，返回最终回复
            assistant_msg = Message(
                role="assistant",
                content=response,
                metadata={"iteration": self.iteration_count}
            )
            self.conversation_history.append(assistant_msg)
            
            # 保存到记忆
            if self.config.memory_enabled and self.memory_manager:
                await self._save_to_memory(user_message, response, user_id)
            
            self._update_state(AgentState.IDLE)
            return response
        
        # 达到最大迭代次数
        self._update_state(AgentState.IDLE)
        return "抱歉，我需要更多时间来思考这个问题。请重新提问或提供更多信息。"
    
    async def _process_stream(self, user_message: str, user_id: Optional[str]) -> AsyncGenerator[str, None]:
        """流式处理消息"""
        # 实现流式处理逻辑
        # 这里简化实现，实际应该支持增量生成
        response = await self._process_message(user_message, user_id)
        
        # 模拟流式输出
        words = response.split()
        for word in words:
            yield word + " "
            await asyncio.sleep(0.05)  # 模拟延迟
    
    async def _build_prompt(self, user_message: str) -> str:
        """构建提示词"""
        prompt_parts = []
        
        # 系统提示词
        if self.config.system_prompt:
            prompt_parts.append(f"系统: {self.config.system_prompt}")
        
        # 工具描述
        if self.tools:
            tool_descriptions = []
            for tool_name, tool in self.tools.items():
                tool_descriptions.append(f"- {tool_name}: {tool.description}")
            
            prompt_parts.append(f"可用工具:\n" + "\n".join(tool_descriptions))
        
        # 记忆检索
        if self.config.memory_enabled and self.memory_manager:
            relevant_memories = await self.memory_manager.search_memories(
                query=user_message,
                limit=5
            )
            if relevant_memories:
                memory_text = "\n".join([mem.content for mem in relevant_memories])
                prompt_parts.append(f"相关记忆:\n{memory_text}")
        
        # 对话历史
        if self.conversation_history:
            history_text = []
            for msg in self.conversation_history[-10:]:  # 只取最近10条
                history_text.append(f"{msg.role}: {msg.content}")
            prompt_parts.append("对话历史:\n" + "\n".join(history_text))
        
        # 当前用户消息
        prompt_parts.append(f"用户: {user_message}")
        prompt_parts.append("助手:")
        
        return "\n\n".join(prompt_parts)
    
    async def _think(self, prompt: str):
        """思考过程"""
        thinking_start = time.time()
        
        # 分析思考
        analysis_thought = Thought(
            type="reasoning",
            content=f"分析用户需求和上下文...",
            confidence=0.8
        )
        self.thoughts.append(analysis_thought)
        
        # 规划思考
        planning_thought = Thought(
            type="planning",
            content=f"规划回复策略和可能的工具使用...",
            confidence=0.7
        )
        self.thoughts.append(planning_thought)
        
        thinking_duration = time.time() - thinking_start
        self.stats["total_thinking_time"] += thinking_duration
        
        log_agent_action(
            agent_id=self.id,
            action="THINK",
            thinking_time=thinking_duration,
            thoughts_count=len(self.thoughts)
        )
    
    async def _generate_response(self, prompt: str) -> str:
        """生成回复"""
        try:
            response = await self.model.generate(prompt)
            return response
        except Exception as e:
            logger.error(f"模型生成失败: {str(e)}")
            raise ModelError(self.config.model, str(e))
    
    def _should_use_tool(self, response: str) -> bool:
        """判断是否需要使用工具"""
        # 简单实现：检查响应中是否包含工具调用标记
        tool_indicators = ["使用工具", "调用", "执行", "查询", "搜索"]
        return any(indicator in response for indicator in tool_indicators)
    
    def _parse_tool_call(self, response: str) -> Optional[Action]:
        """解析工具调用"""
        # 简化实现：从响应中解析工具调用
        # 实际应该使用更复杂的解析逻辑
        
        for tool_name in self.tools.keys():
            if tool_name in response:
                return Action(
                    tool_name=tool_name,
                    parameters={},
                    reasoning=f"从回复中识别需要使用工具: {tool_name}",
                    expected_outcome=f"执行 {tool_name} 工具"
                )
        
        return None
    
    async def _execute_tool(self, action: Action) -> ExecutionResult:
        """执行工具"""
        execution_start = time.time()
        
        try:
            self._update_state(AgentState.ACTING)
            
            if action.tool_name not in self.tools:
                raise ToolError(action.tool_name, "工具不存在")
            
            tool = self.tools[action.tool_name]
            result = await tool.execute(**action.parameters)
            
            execution_duration = time.time() - execution_start
            
            execution_result = ExecutionResult(
                action_id=action.id,
                success=result.success,
                result=result.data,
                error=result.error,
                duration=execution_duration
            )
            
            self.execution_results.append(execution_result)
            self.stats["total_actions"] += 1
            self.stats["total_execution_time"] += execution_duration
            
            if result.success:
                self.stats["successful_actions"] += 1
            else:
                self.stats["failed_actions"] += 1
            
            log_tool_usage(
                agent_id=self.id,
                tool_name=action.tool_name,
                success=result.success,
                duration=execution_duration
            )
            
            return execution_result
        
        except Exception as e:
            execution_duration = time.time() - execution_start
            
            execution_result = ExecutionResult(
                action_id=action.id,
                success=False,
                error=str(e),
                duration=execution_duration
            )
            
            self.execution_results.append(execution_result)
            self.stats["total_actions"] += 1
            self.stats["failed_actions"] += 1
            
            logger.error(f"工具执行失败: {str(e)}")
            return execution_result
        
        finally:
            self._update_state(AgentState.THINKING)
    
    async def _save_to_memory(self, user_message: str, assistant_response: str, user_id: Optional[str]):
        """保存对话到记忆"""
        if self.memory_manager:
            await self.memory_manager.save_conversation(
                agent_id=self.id,
                user_id=user_id,
                user_message=user_message,
                assistant_response=assistant_response
            )
    
    def _update_state(self, new_state: AgentState):
        """更新智能体状态"""
        old_state = self.state
        self.state = new_state
        
        if old_state != new_state:
            log_agent_action(
                agent_id=self.id,
                action="STATE_CHANGE",
                old_state=old_state.value,
                new_state=new_state.value
            )
    
    def _update_stats(self, response_time: float):
        """更新统计信息"""
        self.stats["total_messages"] += 1
        
        # 计算平均响应时间
        total_time = self.stats["average_response_time"] * (self.stats["total_messages"] - 1)
        self.stats["average_response_time"] = (total_time + response_time) / self.stats["total_messages"]
    
    def get_status(self) -> Dict[str, Any]:
        """获取智能体状态"""
        return {
            "id": self.id,
            "name": self.config.name,
            "state": self.state.value,
            "model": self.config.model,
            "iteration_count": self.iteration_count,
            "conversation_length": len(self.conversation_history),
            "tools_count": len(self.tools),
            "stats": self.stats.copy()
        }
    
    def reset_conversation(self):
        """重置对话历史"""
        self.conversation_history.clear()
        self.thoughts.clear()
        self.execution_results.clear()
        self.iteration_count = 0
        self._update_state(AgentState.IDLE)
        
        log_agent_action(
            agent_id=self.id,
            action="RESET_CONVERSATION"
        )
    
    async def stop(self):
        """停止智能体"""
        self._update_state(AgentState.STOPPED)
        
        # 清理资源
        if hasattr(self.model, 'close'):
            await self.model.close()
        
        log_agent_action(
            agent_id=self.id,
            action="STOP"
        )


# 智能体工厂类
class AgentFactory:
    """智能体工厂"""
    
    @staticmethod
    def create_agent(
        config: AgentConfig,
        tools: Optional[Dict[str, BaseTool]] = None,
        memory_manager: Optional[MemoryManager] = None
    ) -> Agent:
        """创建智能体实例"""
        return Agent(config, tools, memory_manager)
    
    @staticmethod
    def create_from_template(
        template_name: str,
        name: str,
        **kwargs
    ) -> Agent:
        """从模板创建智能体"""
        templates = {
            "coding_assistant": AgentConfig(
                name=name,
                description="专业编程助手",
                model="gpt-4",
                temperature=0.1,
                system_prompt="你是一个专业的编程助手，能够帮助用户编写、调试和优化代码...",
                tools=["code_executor", "file_manager", "web_search"],
                thinking_enabled=True
            ),
            "research_assistant": AgentConfig(
                name=name,
                description="研究助手",
                model="claude-3-sonnet",
                temperature=0.3,
                system_prompt="你是一个专业的研究助手，能够帮助用户收集和分析信息...",
                tools=["web_search", "document_analyzer", "summarizer"],
                thinking_enabled=True
            )
        }
        
        if template_name not in templates:
            raise ValueError(f"未知模板: {template_name}")
        
        config = templates[template_name]
        
        # 应用自定义参数
        for key, value in kwargs.items():
            if hasattr(config, key):
                setattr(config, key, value)
        
        return AgentFactory.create_agent(config)


# 导出
__all__ = [
    "Agent",
    "AgentConfig",
    "AgentState",
    "Message",
    "Thought",
    "Action",
    "ExecutionResult",
    "AgentFactory",
]